const _ = require('lodash')
const Mutex = require('promise-mutex')

const MAX_EMOTES_IN_GUILD = 50

class EmoteStore {
  constructor(game, guildIDs) {
    this.game = game
    this.guildIDs = guildIDs
    this.emotes = new Map() // id -> Emoji
    this.mutex = new Mutex()

    this.game.log.info(`Emote store capacity = ${this.guildIDs.length * MAX_EMOTES_IN_GUILD}`)

    if (this.guildIDs.length === 0) {
      throw 'Need at least one emote store server'
    }
  }

  randomClient() {
    return _.sample(this.game.clientPool)
  }

  // Cleans up each emote-storage guild, by removing all channels and emotes
  // present there. RIP.
  async cleanUp() {
    await Promise.all(this.guildIDs.map(guildID => {
      const guild = this.randomClient().guilds.get(guildID)

      return Promise.all([
        ...guild.channels.map(c => c.delete()),
        ...guild.emojis.map(e => guild.deleteEmoji(e)),
      ])
    }))
  }

  // Finds a guild with emote slots available. If there are none, deletes an
  // old emote from a guild.
  async findGuildForNewEmote(makeSlots = false) {
    for (const guildID of _.shuffle(this.guildIDs)) {
      const guild = this.randomClient().guilds.get(guildID)

      if (guild.emojis.size === MAX_EMOTES_IN_GUILD) {
        // Full, make a slot
        if (makeSlots) {
          const emoteToDel = guild.emojis.random()

          this.emotes.delete(emoteToDel.name)
          await guild.deleteEmoji(emoteToDel)
        }
      } else {
        // Has slots, use it
        return guild
      }
    }

    return this.findGuildForNewEmote(true) // Make slots this time
  }

  // Gets an emote by name, uploading it if it isn't found. Returns an Emoji.
  async get(name, graphic) {
    // Don't upload it if it's already there.
    if (this.emotes.has(name)) {
      return this.emotes.get(name)
    }

    // Upload it.
    let emote
    await this.mutex.lock(async () => {
      const guild = await this.findGuildForNewEmote()

      emote = await guild.createEmoji(graphic, name)
    })

    this.emotes.set(name, emote)

    return emote
  }
}

module.exports = EmoteStore
